/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.javahispano.javacup.tacticas.tacticas_aceptadas.Sag;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.javahispano.javacup.modelo.comando.Comando;
import org.javahispano.javacup.modelo.util.Constantes;
import org.javahispano.javacup.modelo.JugadorDetalle;
import org.javahispano.javacup.modelo.util.Posicion;
import org.javahispano.javacup.modelo.engine.SituacionPartido;

/**
 *
 * @author pdsanchez
 */
public abstract class Jugador {
    public static final int TIPO_PORTERO   = 1;
    public static final int TIPO_DEFENSA   = 2;
    public static final int TIPO_CENTRAL   = 3;
    public static final int TIPO_DELANTERO = 4;
    public static final int TIPO_RIVAL     = 5;
    
    private int idx;
    private int tipo;

    private boolean recuperador = false;
    private boolean interceptor = false;
    private boolean rematador   = false;

    private Posicion posReferencia;
    private Posicion posActual;
    private Posicion posDestino;
    private Posicion posBalon;

    private double velocidad;
    private double precision;
    private double remate;

//    private Jugador jAlQueMarco;
    private Jugador marca;
    
    private Jugador[] companerosCercanos;
    private Jugador[] rivalesCercanos;

    protected Jugador[] jugadores;
    protected Jugador[] rivales;
    
    protected SituacionPartido sp;

    public Jugador(int idx, JugadorDetalle detalle, Posicion posRef) {
        this(idx, detalle);
        this.posReferencia = posRef;
        this.posDestino = posRef;
    }

    public Jugador(int idx, JugadorDetalle detalle) {
        this.idx = idx;

        this.velocidad = Constantes.getVelocidad(detalle.getVelocidad());
        this.precision = Constantes.getErrorAngular(detalle.getPresicion());
        this.remate    = Constantes.getVelocidadRemate(detalle.getRemate());
        
        this.companerosCercanos = new Jugador[10];
        this.rivalesCercanos = new Jugador[11];
    }
    
    public int getIndice() {
        return idx;
    }

    public boolean isPortero() {
        return (tipo == TIPO_PORTERO);
    }

    public boolean isDefensa() {
        return (tipo == TIPO_DEFENSA);
    }

    public boolean isCentral() {
        return (tipo == TIPO_CENTRAL);
    }

    public boolean isDelantero() {
        return (tipo == TIPO_DELANTERO);
    }

    public void setTipo(int tipo) {
        this.tipo = tipo;
    }

    public boolean isRecuperador() {
        return recuperador;
    }

    public void setRecuperador(boolean recuperador) {
        this.recuperador = recuperador;
    }

    public Jugador getRecuperador() {
        for (Jugador j : jugadores) {
            if (j.isRecuperador())
                return j;
        }
        return null;
    }

    public boolean isInterceptor() {
        return interceptor;
    }

    public void setInterceptor(boolean interceptor) {
        this.interceptor = interceptor;
    }

    public boolean isRematador() {
        return rematador;
    }

    public void setRematador(boolean rematador) {
        this.rematador = rematador;
    }

    public Jugador getRematador() {
        for (Jugador j : jugadores) {
            if (j.isRematador())
                return j;
        }
        return null;
    }

    public Posicion getPosicionReferencia() {
        return posReferencia;
    }

    public void setPosicionReferencia(Posicion posRef) {
        this.posReferencia = posRef;
    }

    public Posicion getPosicionActual() {
        return posActual;
    }

    public void setPosicionActual(Posicion posActual) {
        this.posActual = posActual;
    }

    public Posicion getPosicionBalon() {
        return posBalon;
    }
    
    public Posicion getPosicionDestino() {
        return posDestino;
    }

    public void setPosicionDestino(Posicion posDestino) {
        this.posDestino = posDestino.setDentroCampoJuego();
    }

    public void setPosicionDestino(double x, double y) {
        //this.posDestino.setPosicion(x, y);
        this.posDestino = new Posicion(x, y).setDentroCampoJuego();
    }

    /**
     * @return la velocidad
     */
    public double getVelocidad() {
        return velocidad;
    }

    /**
     * @return la precision
     */
    public double getPrecision() {
        return precision;
    }

    /**
     * @return la potencia de remate
     */
    public double getRemate() {
        return remate;
    }

    public int getIteracionesAPosDestino() {
        //return (int) ( (posActual.distancia(posDestino) - Constantes.DISTANCIA_CONTROL_BALON ) / velocidad);
        return (int) (posActual.distancia(posDestino) / velocidad);
    }

    public boolean estaBalonEnCampoRival(){
        return (posBalon.getY() >= 0);
    }

    public boolean estaJugadorEnCampoRival(){
        return (posActual.getY() >= 0);
    }

//    public void setJugadorAlQueMarca(Jugador j) {
//        jAlQueMarco = j;
//    }
//
//    public Jugador getJugadorAlQueMarca() {
//        return jAlQueMarco;
//    }
//
//    public boolean estaMarcandoAOtroJugador() {
//        return (jAlQueMarco != null);
//    }

    public Jugador getMarcaje() {
        return marca;
    }

    public void setMarcaje(Jugador j) {
        marca = j;
    }

    public boolean existeMarcaje() {
        return (marca != null);
    }

    public Jugador[] getCompanerosCercanos() {
        return companerosCercanos;
    }

    public Jugador getCompaneroMasCercano() {
        return companerosCercanos[0];
    }

    public boolean existeCompaneroCercano() {
        return (companerosCercanos.length > 0);
    }

    public Jugador[] getRivalesCercanos() {
        return rivalesCercanos;
    }

    public Jugador getRivalMasCercano() {
        return rivalesCercanos[0];
    }

    public boolean existeRivalCercano() {
        return (rivalesCercanos.length > 0);
    }

    /**
     * @return El companero mas cercano a la posicion especificada
     */
    public Jugador getCompanero(Posicion pos) {
        return jugadores[pos.indiceMasCercano(sp.misJugadores())];
    }

    /**
     * @return El rival mas cercano a la posicion especificada
     */
    public Jugador getRival(Posicion pos) {
        return rivales[pos.indiceMasCercano(sp.rivales())];
    }

    /**
     * @return El portero de mis jugadores
     */
    public Jugador getPortero() {
        for (Jugador j : jugadores) {
            if (j.isPortero()) return j;
        }
        return null;
    }

    /**
     * @return Lista con mis defensas
     */
    public List<Jugador> getDefensas() {
        List<Jugador> l = new ArrayList<Jugador>();
        for (Jugador j : jugadores) {
            if (j.isDefensa()) {
                l.add(j);
            }
        }
        return l;
    }

    /**
     * @return Lista con mis centrales
     */
    public List<Jugador> getCentrales() {
        List<Jugador> l = new ArrayList<Jugador>();
        for (Jugador j : jugadores) {
            if (j.isCentral()) {
                l.add(j);
            }
        }
        return l;
    }

    /**
     * @return Lista con mis delanteros
     */
    public List<Jugador> getDelanteros() {
        List<Jugador> l = new ArrayList<Jugador>();
        for (Jugador j : jugadores) {
            if (j.isDelantero()) {
                l.add(j);
            }
        }
        return l;
    }

    /**
     * @return El portero rival
     */
    public Jugador getPorteroRival() {
        for (Jugador j : rivales) {
            if (j.isPortero()) return j;
        }
        return null;
    }

    public void update(SituacionPartido sp, Jugador[] jugadores, Jugador[] rivales) {
        this.sp = sp;
        this.jugadores = jugadores;
        this.rivales = rivales;
        
        // Resetear
        recuperador = false;
        interceptor = false;
        rematador = false;
        posActual = (tipo == TIPO_RIVAL) ? sp.rivales()[idx] : sp.misJugadores()[idx];
        //posActual = posJugadores[idx];
        posBalon = sp.balon();

//        jAlQueMarco = null;
        marca = null;
        
        // Posiciones de los jugadores
        Posicion[] posJugadores = (tipo == TIPO_RIVAL) ? sp.rivales(): sp.misJugadores();
        Posicion[] posJugadoresRivales = (tipo == TIPO_RIVAL) ? sp.misJugadores() : sp.rivales();

        // Companeros cercanos
        int[] idxList = posActual.indicesMasCercanos(posJugadores);
        int idxReal = 0;
        for (int i=0; i<idxList.length; i++) {
            // No usar a este jugador
            if (this.getIndice() != idxList[i]) {
                companerosCercanos[idxReal] = jugadores[idxList[i]];
                idxReal++;
            }
        }
        // Rivales cercanos
        idxList = posActual.indicesMasCercanos(posJugadoresRivales);
        for (int i=0; i<idxList.length; i++) {
            rivalesCercanos[i] = rivales[idxList[i]];
        }

        // Este jugador esta marcado si existe un rival a menos de una distancia concreta
        double dist = posActual.distancia(this.getRivalMasCercano().getPosicionActual());
        if (dist <= 15) {
            marca = this.getRivalMasCercano();
        }
    }

    public abstract Comando irAPosicionDestino();
    public abstract Comando GolpearBalon();

    public void evaluarRecuperacion(Posicion posRc, Jugador rival, Jugador otroRecuperador) {
        posDestino = posRc;
        otroRecuperador.setPosicionDestino(posRc);

        // Si el otro recuperador es portero, lo descarto
        if (otroRecuperador.isPortero()) {
            recuperador = true;
        }
        // Este jugador es el recuperador mas rapido
        else if(this.getIteracionesAPosDestino() <= otroRecuperador.getIteracionesAPosDestino()) {
            recuperador = true;

            // El recuperador rival mas proximo
            rival.setPosicionDestino(posRc);

            // Determinar de quien es la ventaja en la recuperacion
            int ventaja = this.getIteracionesAPosDestino() - rival.getIteracionesAPosDestino();

            // Ventaja rival
            if (ventaja >= 0) {
                // Si este jugador es portero, lo mantengo en porteria y uso otro recuperador
                if (this.isPortero()) {
                    otroRecuperador.setRecuperador(true);
                    recuperador = false;
                }
            }
            // Ventaja mia, pero soy portero y lejos del area
            else if (this.isPortero() && Math.abs(posRc.getX()) > 15) {
                otroRecuperador.setRecuperador(true);
                recuperador = false;
            }
        }
        // El otro recuperador no es portero y es más rapido (lo uso)
        else {
            otroRecuperador.setRecuperador(true);
            otroRecuperador.setPosicionDestino(posRc);
        }
    }

    public void evaluarIntercepcion(Posicion posRc, Jugador otroInterceptor, int iteracion) {
        Jugador itc = this;
        // Si este jugador es receptor o portero no puede ser tambien interceptor
        if (this.isRecuperador() || this.isPortero()) {
            itc = otroInterceptor;
        }
        
        // Ver si realmente es interceptor
        itc.setPosicionDestino(posRc);
        
        // Si este jugador llega antes que el balon a la posicion de intercepcion
        // lo marco como interceptor
        if (itc.getIteracionesAPosDestino() <= iteracion) {
            itc.setInterceptor(true);
        }
    }


    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        if (tipo == TIPO_RIVAL) {
            sb.append("> Rival").append(idx);
            if (isPortero()) {
                sb.append(" [portero]");
            }
        }
        else {
            sb.append("> Jugador").append(idx).append(" [T").append(tipo).append("]");
        }
        sb.append(" Rc").append(this.isRecuperador() ? "1" : "0");
        sb.append(" Ic").append(this.isInterceptor() ? "1" : "0");
        sb.append(" Rt").append(this.isRematador() ? "1" : "0");
        if (this.existeMarcaje()) {
            sb.append(" Marca").append(this.getMarcaje().traza());
        }
        else {
            sb.append(" Sin marca");
        }
        //sb.append(" (Rival cercano").append(this.getRivalMasCercano().traza()).append(")");
        
        return sb.toString();
    }

    public String traza() {
        StringBuilder sb = new StringBuilder();
        if (tipo == TIPO_RIVAL) {
            sb.append("> Rival").append(idx);
            if (isPortero()) {
                sb.append(" [portero]");
            }
        }
        else {
            sb.append("> Jugador").append(idx).append(" [T").append(tipo).append("]");
        }

        return sb.toString();
    }
}
